﻿using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Globalization;

namespace GarminUploader.Connector
{
    public class GarminConnector : BaseConnector
    {
        // The required base URL
        protected override string baseUrl { get { return "https://connect.garmin.com"; } }

        // URL strings
        private readonly string LOGIN_URL = "/signin";
        private readonly string LIST_URL = "/proxy/activity-search-service-1.2/json/activities";
        private readonly string UPLOAD_URL = "/proxy/upload-service-1.1/json/upload";

        public override void login(string username, string password)
        {
            // Get the login page
            HttpResponseMessage result = client.GetAsync(LOGIN_URL).Result;

            // Perform the actual log in
            loginPost(username, password);

            // Set the internal variables
            loggedIn = true;
        }

        private void loginPost(string username, string password)
        {
            // Construct the content
            FormUrlEncodedContent content = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("login", "login"),
                new KeyValuePair<string, string>("login:loginUsernameField", username),
                new KeyValuePair<string, string>("login:password", password),
                new KeyValuePair<string, string>("login:signInButton", "Sign In"),
                new KeyValuePair<string, string>("javax.faces.ViewState", "j_id1")
            });

            // Do the POST
            HttpResponseMessage result = client.PostAsync(LOGIN_URL, content).Result;

            // Check the response Uri
            if (result.RequestMessage.RequestUri.ToString().Equals(LOGIN_URL))
            {
                throw new UserLoginException(username, LOGIN_URL);
            }
        }

        public override List<DateTime> listActivityStartTimes()
        {
            // Throw error if user isn't logged in
            checkLogin();

            // Return type
            List<DateTime> activityStartTimes = new List<DateTime>();

            // Get the activities
            HttpResponseMessage result = client.GetAsync(LIST_URL).Result;

            // Deserialise the JSON response
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            var json = serializer.Deserialize<dynamic>(result.Content.ReadAsStringAsync().Result);

            // Add the ID to the array for each activity
            foreach (var activity in json["results"]["activities"])
            {
                // Get the start time
                string time = activity["activity"]["activitySummary"]["BeginTimestamp"]["value"];
                activityStartTimes.Add(DateTime.Parse(time).ToUniversalTime());
            }

            // return all external ids
            return activityStartTimes;
        }

        public override void upload(FitFile file)
        {
            // Throw error if user isn't logged in
            checkLogin();

            // Add the post data
            ByteArrayContent content = new ByteArrayContent(file.getBytes());
            content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

            // Post the page
            HttpResponseMessage result = client.PostAsync(UPLOAD_URL, content).Result;
            string responseString = result.Content.ReadAsStringAsync().Result;

            // Deserialise the JSON response
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            var json = serializer.Deserialize<dynamic>(responseString);

            // Throw an exception if there were any failures
            var failures = json["detailedImportResult"]["failures"];
            if (failures != null && failures.Length > 0)
            {
                // Get the error message
                string error = failures[0]["messages"][0]["content"];

                // Throw a special exception if the file is a duplicate
                if (error.Contains("Duplicate"))
                {
                    throw new DuplicateActivityException(error);
                }
                else
                {
                    throw new ActivityUploadException("Upload failed: " + failures[0]["messages"][0]["content"]);
                }
            }
        }
    }
}